#include "napi/native_api.h"
#include <chrono>
#include <functional>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <thread>

#include "logan_queue.h"
#include <clogan_core.h>

// JS回调函数的引用
static napi_ref js_callback_ref = nullptr;
static napi_env g_env = nullptr;
static napi_threadsafe_function tsfn = nullptr; // 线程安全函数

// JS回调函数封装
struct CallbackData {
    std::string cmd;
    int code;
};

static void JSLoganCallbackWrapper(const std::string &cmd, int code) {
    if (tsfn == nullptr) {
        return;
    }

    // 创建回调数据
    CallbackData *data = new CallbackData{cmd, code};

    // 调用线程安全函数
    napi_call_threadsafe_function(tsfn, data, napi_tsfn_nonblocking);
}

// 线程安全函数的回调
static void CallJSFunction(napi_env env, napi_value js_callback, void *context, void *data) {
    CallbackData *callbackData = static_cast<CallbackData *>(data);

    if (env != nullptr && js_callback != nullptr) {
        // 准备参数
        napi_value argv[2];
        napi_create_string_utf8(env, callbackData->cmd.c_str(), callbackData->cmd.length(), &argv[0]);
        napi_create_int32(env, callbackData->code, &argv[1]);

        // 调用JS回调函数
        napi_value result;
        napi_call_function(env, nullptr, js_callback, 2, argv, &result);
    }

    // 释放数据
    delete callbackData;
}

static napi_value LogInit(napi_env env, napi_callback_info info) {
    size_t argc = 1;
    napi_value args[1] = {nullptr};

    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    if (argc < 1) {
        napi_throw_error(env, nullptr, "Wrong number of arguments");
        return nullptr;
    }

    // 获取LoganConfig对象
    napi_value configObj = args[0];

    // 获取cachePath属性
    napi_value cachePathValue;
    napi_get_named_property(env, configObj, "cachePath", &cachePathValue);
    size_t cachePathLength;
    napi_get_value_string_utf8(env, cachePathValue, nullptr, 0, &cachePathLength);
    char *cachePath = (char *)malloc(cachePathLength + 1);
    napi_get_value_string_utf8(env, cachePathValue, cachePath, cachePathLength + 1, &cachePathLength);

    // 获取pathPath属性
    napi_value pathPathValue;
    napi_get_named_property(env, configObj, "dirPath", &pathPathValue);
    size_t pathPathLength;
    napi_get_value_string_utf8(env, pathPathValue, nullptr, 0, &pathPathLength);
    char *pathPath = (char *)malloc(pathPathLength + 1);
    napi_get_value_string_utf8(env, pathPathValue, pathPath, pathPathLength + 1, &pathPathLength);

    // 获取maxFile属性
    napi_value maxFileValue;
    napi_get_named_property(env, configObj, "maxFile", &maxFileValue);
    int maxFile;
    napi_get_value_int32(env, maxFileValue, &maxFile);

    // 获取free属性
    napi_value freeFileValue;
    napi_get_named_property(env, configObj, "free", &freeFileValue);
    long freeStorage;
    napi_get_value_int64(env, freeFileValue, &freeStorage);

    // 获取day属性
    napi_value dayValue;
    napi_get_named_property(env, configObj, "day", &dayValue);
    int day;
    napi_get_value_int32(env, dayValue, &day);

    // 获取maxQueue属性
    napi_value maxQueueValue;
    napi_get_named_property(env, configObj, "maxQueue", &maxQueueValue);
    int maxQueue;
    napi_get_value_int32(env, maxQueueValue, &maxQueue);

    // 获取minSDCard属性
    napi_value minSDCardValue;
    napi_get_named_property(env, configObj, "minSDCard", &minSDCardValue);
    int minSDCard;
    napi_get_value_int32(env, minSDCardValue, &minSDCard);

    // 获取encryptKey16属性 (string)
    napi_value encryptKey16Value;
    napi_get_named_property(env, configObj, "encryptKey16", &encryptKey16Value);
    size_t encryptKey16Length;
    napi_get_value_string_utf8(env, encryptKey16Value, nullptr, 0, &encryptKey16Length);
    char *encryptKey16 = (char *)malloc(encryptKey16Length + 1);
    napi_get_value_string_utf8(env, encryptKey16Value, encryptKey16, encryptKey16Length + 1, &encryptKey16Length);

    // 获取encryptIv16属性 (string)
    napi_value encryptIv16Value;
    napi_get_named_property(env, configObj, "encryptIv16", &encryptIv16Value);
    size_t encryptIv16Length;
    napi_get_value_string_utf8(env, encryptIv16Value, nullptr, 0, &encryptIv16Length);
    char *encryptIv16 = (char *)malloc(encryptIv16Length + 1);
    napi_get_value_string_utf8(env, encryptIv16Value, encryptIv16, encryptIv16Length + 1, &encryptIv16Length);
    // 调用C接口初始化日志系统
    int result = clogan_init(cachePath, pathPath, maxFile, encryptKey16, encryptIv16);
    // 调用JS回调函数
    JSLoganCallbackWrapper("clogan_init", result);
    if (freeStorage > minSDCard) {
        // 初始化并启动日志队列系统
        if (result == -1010) {
            LoganQueue::getInstance().init(maxQueue, day, pathPath); // 使用配置中的队列大小和保存天数
            LoganQueue::getInstance().startWriterThread();
        }
    }

    free(cachePath);
    free(pathPath);
    free(encryptKey16);
    free(encryptIv16);

    // 返回结果
    napi_value napiResult;
    napi_create_int32(env, result, &napiResult);
    return napiResult;
}

static napi_value LogWrite(napi_env env, napi_callback_info info) {
    size_t argc = 2;
    napi_value args[2] = {nullptr};

    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    if (argc < 2) {
        napi_throw_error(env, nullptr, "Wrong number of arguments");
        return nullptr;
    }

    // 获取日志等级
    int level;
    napi_get_value_int32(env, args[0], &level);

    // 获取日志内容参数
    size_t contentLength;
    napi_get_value_string_utf8(env, args[1], nullptr, 0, &contentLength);
    char *content = (char *)malloc(contentLength + 1);
    napi_get_value_string_utf8(env, args[1], content, contentLength + 1, &contentLength);
    std::thread::id id = std::this_thread::get_id();
    // 获取当前线程信息
    char threadName[32];
    snprintf(threadName, sizeof(threadName), "thread_%lu",
             static_cast<unsigned long>(std::hash<std::thread::id>{}(id)));

    // 获取当前时间戳
    auto now =
        std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch())
            .count();

    // 将日志写入操作添加到队列（非阻塞）
    bool result = LoganQueue::getInstance().addLogWrite(level, content, now, threadName,
                                                        static_cast<long long>(std::hash<std::thread::id>{}(id)));

    free(content);

    // 返回结果
    napi_value napiResult;
    napi_create_int32(env, result ? 1 : 0, &napiResult);
    return napiResult;
}

static napi_value LogFlush(napi_env env, napi_callback_info info) {
    // 将日志刷新操作添加到队列（非阻塞）
    bool result = LoganQueue::getInstance().addLogFlush();

    // 返回结果
    napi_value napiResult;
    napi_create_int32(env, result ? 1 : 0, &napiResult);
    return napiResult;
}

static napi_value LogSetDebug(napi_env env, napi_callback_info info) {
    size_t argc = 1;
    napi_value args[1] = {nullptr};

    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    if (argc < 1) {
        napi_throw_error(env, nullptr, "Wrong number of arguments");
        return nullptr;
    }

    // 获取调试模式
    int32_t debug;
    napi_get_value_int32(env, args[0], &debug);

    // 调用C接口设置调试模式
    clogan_debug(debug);

    // 设置队列系统的调试模式
    LoganQueue::getInstance().setDebug(debug);

    return nullptr;
}

static napi_value RegisterJSLoganCallback(napi_env env, napi_callback_info info) {
    size_t argc = 1;
    napi_value args[1] = {nullptr};

    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    if (argc < 1) {
        napi_throw_error(env, nullptr, "Wrong number of arguments");
        return nullptr;
    }

    // 保存环境
    g_env = env;

    // 如果已存在线程安全函数，先释放它
    if (tsfn != nullptr) {
        napi_release_threadsafe_function(tsfn, napi_tsfn_release);
        tsfn = nullptr;
    }

    // 如果已存在引用，先删除它
    if (js_callback_ref != nullptr) {
        napi_delete_reference(env, js_callback_ref);
        js_callback_ref = nullptr;
    }

    // 创建回调函数的引用
    napi_create_reference(env, args[0], 1, &js_callback_ref);

    // 定义资源名称
    napi_value resource_name;
    napi_create_string_utf8(env, "c_api_status", NAPI_AUTO_LENGTH, &resource_name);
    
    // 创建线程安全函数
    napi_value js_callback = args[0];
    napi_create_threadsafe_function(env, js_callback, nullptr, resource_name, 0, 1, nullptr, nullptr, nullptr, CallJSFunction,
                                    &tsfn);

    // 注册C++层的回调函数
    LoganQueue::getInstance().registerJSLoganCallback(JSLoganCallbackWrapper);

    return nullptr;
}

EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports) {
    // 定义导出的方法
    napi_property_descriptor desc[] = {
        {"init", nullptr, LogInit, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"write", nullptr, LogWrite, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"flush", nullptr, LogFlush, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"setDebug", nullptr, LogSetDebug, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"setOnLoganProtocolStatus", nullptr, RegisterJSLoganCallback, nullptr, nullptr, nullptr, napi_default,
         nullptr}};
    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
    return exports;
}
EXTERN_C_END

static napi_module loganModule = {
    .nm_version = 1,
    .nm_flags = 0,
    .nm_filename = nullptr,
    .nm_register_func = Init,
    .nm_modname = "logan",
    .nm_priv = ((void *)0),
    .reserved = {0},
};

extern "C" __attribute__((constructor)) void RegisterLibraryModule(void) { napi_module_register(&loganModule); }

